package com.yunlongn.async.idempotent;


import com.yunlongn.async.action.RetryActionWarp;
import com.yunlongn.async.config.RetrySchedulerConfig;
import com.yunlongn.async.function.RetryActionAdapter;
import com.yunlongn.async.function.RetryScheduleAction;
import com.yunlongn.async.idempotent.filter.IdempotentFilter;
import com.yunlongn.async.idempotent.filter.MemoryIdempotentFilter;
import com.yunlongn.async.idempotent.filter.RedisIdempotentFilter;
import com.yunlongn.async.log.RetryScheduleLogService;
import com.yunlongn.async.log.impl.MemoryScheduleServiceImpl;
import com.yunlongn.async.log.impl.RedisScheduleServiceImpl;
import com.yunlongn.async.util.spi.SpiLoader;
import com.yunlongn.async.util.spi.SpiOrder;

import java.util.concurrent.TimeUnit;

/**
 * Id幂等过滤器
 *
 * @author yunlongn
 */
@SpiOrder(0)
public class IdempotentActionWarp implements RetryActionWarp {

    private static IdempotentFilter IDEMPOTENT_FILTER;

    static {
        IDEMPOTENT_FILTER = SpiLoader.loadFistNotDefaultService(IdempotentFilter.class.getClassLoader(),
                IdempotentFilter.class, RedisIdempotentFilter.class);
        if (RetrySchedulerConfig.getStringRedisTemplate() == null) {
            IDEMPOTENT_FILTER = SpiLoader.loadFistNotDefaultService(Thread.currentThread().getContextClassLoader(),
                    IdempotentFilter.class, MemoryIdempotentFilter.class);
        }
    }

    @Override
    public <T> RetryScheduleAction<T> warpAction(String retrySubmitId, RetryScheduleAction<T> action, TimeUnit timeUnit, int... periods) {
        if (retrySubmitId != null && IDEMPOTENT_FILTER.needFilter(retrySubmitId, timeUnit, periods)) {
            // ID 已存在redis中。说明已经有同个id的任务了。那么进行报错
            throw new RuntimeException("任务 ID = " + retrySubmitId + "已存在");
        }
        return new RetryActionAdapter<T>(action) {

            @Override
            public boolean execute(T param) {
                boolean result = super.execute(param);
                if (result) {
                    // 成功时移除幂等标志
                    IDEMPOTENT_FILTER.remove(retrySubmitId);
                }
                return result;
            }

            @Override
            public void onFail() {
                try {
                    super.onFail();
                } finally {
                    // 最后一次重试也失败了，移除幂等标志
                    IDEMPOTENT_FILTER.remove(retrySubmitId);
                }
            }

        };
    }
}
